<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/10/10
 * Time: 17:26
 */

namespace App\Services;

use App\Models\Attach;
use Illuminate\Http\File;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;

class AttachService extends BaseService
{
    protected $modelClass = Attach::class;
    protected $adminService;

    public function __construct(AdminService $adminService)
    {
        $this->adminService = $adminService;
        parent::__construct();
    }

    /**
     * @desc 向文件中写入数据
     * @param $path
     * @param $data
     * @return mixed
     */
    public function writeData($path, $data)
    {
        Storage::put($path, $data);
        return Storage::url($path);
    }

    /**
     * @desc 向文件中追加数据
     * @param $path
     * @param $data
     * @return mixed
     */
    public function appendData($path, $data)
    {
        Storage::append($path, $data);
        return Storage::url($path);
    }

    /**
     * @desc 向文件前插入数据
     * @param $path
     * @param $data
     * @return mixed
     */
    public function preAppendData($path, $data)
    {
        Storage::prepend($path, $data);
        return Storage::url($path);
    }

    /**
     * @desc 上传图片，文件
     * @param string $path
     * @param bool $newName
     * @param array $ext
     * @param float|int $limit
     * @return array|bool|string
     * @throws \Exception
     */
    public function uploadImg($path='images', $newName=true, $ext=['.jpg', '.png', '.jpeg'], $limit=10*1024)
    {
        if ($file = request()->file) {
            if (is_array($file)) {
                $result = [];
                array_walk($file, function ($file) use (&$result, $path, $newName, $ext, $limit) {
                    if ($data = $this->saveFile($file, $newName, $path, $ext, $limit)) {
                        array_push($result, $data);
                    }
                });

                return $result;
            } else {
                if ($path = $this->saveFile($file, $newName, $path, $ext, $limit)) {
                    return $path;
                }
            }
        }
    }

    /**
     * @desc 保存文件
     * @param $file
     * @param $newName
     * @param $path
     * @param $ext
     * @param $limit
     * @return array|bool
     * @throws \Exception
     */
    private function saveFile($file, $newName=true, $path, $ext, $limit)
    {
        $path = $path.'/'.date('Ym');

        if ($file instanceof UploadedFile) {
            if ($file->isValid()) {
                $origin_name = $file->getClientOriginalName();

                $kb = (int)$file->getSize()/1024;
                if ($kb > $limit) {
                    throw new \Exception('上传文件大小超过限制');
                }

                preg_match('|\.(\w+)$|', $origin_name, $ext_arr);
                $e = strtolower($ext_arr[0]);
                if (!in_array($e, $ext)) {
                    throw new \Exception("不允许上传{$e}文件");
                }

                $md5File = md5_file($file->getPathname());

                if (!$obj = $this->model->where('file_md5', $md5File)->first()) {
                    if ($newName) { # 需要重命名的
                        $link = Storage::putFileAs($path, new File($file->getPathname()), unique_key()."{$e}");
                        if ($link) {
                            $linkArr = explode('/', $link);
                            $name = $linkArr[count($linkArr)-1];
                        }
                    } else {
                        $link = Storage::putFileAs($path, new File($file->getPathname()), $origin_name);
                    }

                    if ($link === false) {
                        return false;
                    }

                    if ($e=='.doc' or $e=='.docx') {
                        $suffix = 'doc';
                    }
                    if ($e=='.xls' or $e=='.xlsx') {
                        $suffix = 'excel';
                    }
                    if ($e=='.zip' or $e=='.rar') {
                        $suffix = 'zip';
                    }

                    $member = $this->adminService->member();

                    $data = [
                        'user_id' => $member->admin_id,
                        'username' => $member->username,
                        'file_size' => $kb,
                        'filename' => $name ?? $origin_name,
                        'origin_name' => $origin_name,
                        'file_md5' => $md5File,
                        'file_path' => $link,
                        'suffix' => $suffix,
                    ];

                    $obj = $this->saveData($data);
                }

                return [
                    'id' => $obj->id,
                    'origin_name' => $obj->origin_name,
                    'file_path' => $obj->file_path,
                    'attach_url' => $obj->attach_url,
                ];
            }
        }

        return false;
    }

    /**
     * 删除附件
     * @param $uuid
     * @return mixed
     * @throws \Exception
     */
    public function remove($uuid)
    {
        try {
            return $this->removeByUuid($uuid);
        } catch (\Exception $e) {
            throw new \Exception('删除失败！');
        }
    }

    /**
     * 获取下载链接
     * @param $id
     * @return bool|string
     * @throws \Exception
     */
    public function download($id)
    {
        if ($this->findByIdOrFail($id)) {
            Cache::put('download:'.$id, $id, 5);

            return config('app.url'). 'admin/attach/downFile/'.$id;
        }

        return false;
    }

    /**
     * @param $id
     * @return mixed
     * @throws \Exception
     */
    public function downFile($id)
    {
        if (Cache::has('download:' . $id)) {
            $file = $this->findByIdOrFail($id);

            Cache::forget('download:' . $id);//清除缓存 只允许下载一次

            return $file;
        }

        throw new \Exception('非法请求或您已下载过');
    }

    /**
     * @desc 列表
     * @param array $search
     * @param int $per_page
     * @return array
     */
    public function getList($search=[], $per_page=20)
    {
        $columns = ['*'];

        $model = $this->searcher($this->model, $search);

        $conf = [
            'search'  => 'conf_search.attach_getList',
            'columns' => 'conf_columns.attach_getList',
            'buttons' => 'conf_buttons.attach_getList',
        ];
        return $this->get_paginate($model->paginate($per_page, $columns), $conf);
    }

}
